Skip to content

fix(daemon): drop prior session when agent is renamed (MUL-5736) - #5909

Open
kakiuwang-ui wants to merge 1 commit into
multica-ai:mainfrom
kakiuwang-ui:fix/5736-agent-identity-rename-drop
Open

fix(daemon): drop prior session when agent is renamed (MUL-5736)#5909
kakiuwang-ui wants to merge 1 commit into
multica-ai:mainfrom
kakiuwang-ui:fix/5736-agent-identity-rename-drop

Conversation

@kakiuwang-ui

Copy link
Copy Markdown
Contributor

Summary

  • When an agent is renamed (e.g. "Reviewer" → "Backend Builder"), the workdir from its last run still holds a runtime config (CLAUDE.md / AGENTS.md) whose ## Agent Identity section records the old name. Resuming that session causes the conversation history to assert the old identity; even though InjectRuntimeConfig overwrites the file with the new name, the resumed turns have already established the wrong role — which is why Backend Builder called itself "Reviewer" and refused tasks in MUL-5736.
  • Before overwriting the runtime config, gateResumeToSameAgentName reads the name from the existing managed marker block. A mismatch drops PriorSessionID and clears PriorSessionResumed, so the run starts fresh with the correct identity.
  • ReadPriorAgentName is added to execenv so the parse logic is independently testable.
  • The drop does not set PriorSessionResumeUnavailable — an agent rename is intentional, so a fresh session is the expected outcome, not a loss to disclose.

Test plan

  • TestReadPriorAgentName — verifies correct extraction of the agent name from the managed block for all edge cases (name with/without ID suffix, missing file, no marker block, no identity section, unknown provider).
  • TestGateResumeToSameAgentName — verifies the gate drops the session on name change, keeps it on match, and is a no-op when there is no prior session, no current agent name, or no config file.
  • Full ./server/internal/daemon/... suite passes.

…tity contamination (MUL-5736)

When an agent is renamed (e.g. "Reviewer" → "Backend Builder"), the workdir
from its last run still holds a CLAUDE.md whose ## Agent Identity section names
the old role. Resuming that session means the conversation history has already
established the old identity, causing the agent to misidentify itself and refuse
tasks — the behaviour reported in MUL-5736.

Fix: before overwriting CLAUDE.md with the new identity, read the name already
recorded in the managed marker block. If it differs from the current agent name,
drop PriorSessionID and start a fresh conversation. The check runs after
gateCodexResumeToRolloutPresence while the old file is still on disk.

The drop does not set PriorSessionResumeUnavailable because a rename is
intentional: the user changed the agent's identity on purpose, so a fresh
session is expected behaviour rather than an unexpected loss to surface.

ReadPriorAgentName is added to execenv so the parsing logic is testable in
isolation; gateResumeToSameAgentName wraps the daemon-level gate.
@vercel

vercel Bot commented Jul 24, 2026

Copy link
Copy Markdown

@kakiuwang-ui is attempting to deploy a commit to the IndexLabs Team on Vercel.

A member of the Team first needs to authorize it.

kakiuwang-ui added a commit to kakiuwang-ui/multica that referenced this pull request Aug 3, 2026
…multica-ai#5760)

Reduced to the ACP-sniffer half per maintainer guidance on multica-ai#5785: the
poisoned-session classification (classifyPoisonedError branches), the
session-exclusion queries, and the daemon carry-forward are all dropped —
multica-ai#6083 (taskfailure.UnresumableHistory) and migration 234
(retired_session_id) now own that layer on main. The agent-rename gate
(MUL-5736) is tracked separately in multica-ai#5909.

What remains is the non-redundant fix nothing on main replaces: the ACP
adapter was swallowing the provider error and reporting stopReason=end_turn,
so a kimi 400 landed as status=completed with empty output. Everything in
multica-ai#6083 keys off Result.Error; if the adapter never surfaces the error there,
none of it can see the failure.

- acpErrorHeaderRe / acpErrorDetailRe / acpTerminalErrorRe now recognise
  kimi's emoji-less `provider.api_error: NNN` lines; terminal only for
  400/401/403 (429/408 are adapter-retried and must stay completed).
- messageLocked forwards the status prefix via providerApiErrorStatusRe so
  the surfaced Result.Error carries `provider.api_error: 400`, which
  taskfailure.UnresumableHistory on main then classifies.
- isPoisonedHistory() detects the 400 + "must not be empty" fingerprint
  across kimi's two-line stderr format and sets Result.ResumeRejected in
  both the hermes and kimi backends — the positive backend signal the
  daemon reads alongside the string-based path.

Tests: ACP sniffer recognition (400/5xx/429), isPoisonedHistory two-line
detection, messageLocked status forwarding, and hermes/kimi backend
ResumeRejected (set on resume, not on a fresh run).
kakiuwang-ui added a commit to kakiuwang-ui/multica that referenced this pull request Aug 3, 2026
…multica-ai#5760)

Reduced to the ACP-sniffer half per maintainer guidance on multica-ai#5785: the
poisoned-session classification (classifyPoisonedError branches), the
session-exclusion queries, and the daemon carry-forward are all dropped —
multica-ai#6083 (taskfailure.UnresumableHistory) and migration 234
(retired_session_id) now own that layer on main. The agent-rename gate
(MUL-5736) is tracked separately in multica-ai#5909.

What remains is the non-redundant fix nothing on main replaces: the ACP
adapter was swallowing the provider error and reporting stopReason=end_turn,
so a kimi 400 landed as status=completed with empty output. Everything in
multica-ai#6083 keys off Result.Error; if the adapter never surfaces the error there,
none of it can see the failure.

- acpErrorHeaderRe / acpErrorDetailRe / acpTerminalErrorRe now recognise
  kimi's emoji-less `provider.api_error: NNN` lines; terminal only for
  400/401/403 (429/408 are adapter-retried and must stay completed).
- messageLocked forwards the status prefix via providerApiErrorStatusRe so
  the surfaced Result.Error carries `provider.api_error: 400`, which
  taskfailure.UnresumableHistory on main then classifies.
- isPoisonedHistory() detects the 400 + "must not be empty" fingerprint
  across kimi's two-line stderr format and sets Result.ResumeRejected in
  both the hermes and kimi backends — the positive backend signal the
  daemon reads alongside the string-based path.

Tests: ACP sniffer recognition (400/5xx/429), isPoisonedHistory two-line
detection, messageLocked status forwarding, and hermes/kimi backend
ResumeRejected (set on resume, not on a fresh run).
kakiuwang-ui added a commit to kakiuwang-ui/multica that referenced this pull request Aug 9, 2026
…multica-ai#5760)

Reduced to the ACP-sniffer half per maintainer guidance on multica-ai#5785: the
poisoned-session classification (classifyPoisonedError branches), the
session-exclusion queries, and the daemon carry-forward are all dropped —
(retired_session_id) now own that layer on main. The agent-rename gate
(MUL-5736) is tracked separately in multica-ai#5909.

What remains is the non-redundant fix nothing on main replaces: the ACP
adapter was swallowing the provider error and reporting stopReason=end_turn,
so a kimi 400 landed as status=completed with empty output. Everything in
none of it can see the failure.

- acpErrorHeaderRe / acpErrorDetailRe / acpTerminalErrorRe now recognise
  kimi's emoji-less `provider.api_error: NNN` lines; terminal only for
  400/401/403 (429/408 are adapter-retried and must stay completed).
- messageLocked forwards the status prefix via providerApiErrorStatusRe so
  the surfaced Result.Error carries `provider.api_error: 400`, which
  taskfailure.UnresumableHistory on main then classifies.
- isPoisonedHistory() detects the 400 + "must not be empty" fingerprint
  across kimi's two-line stderr format and sets Result.ResumeRejected in
  both the hermes and kimi backends — the positive backend signal the
  daemon reads alongside the string-based path.

Tests: ACP sniffer recognition (400/5xx/429), isPoisonedHistory two-line
detection, messageLocked status forwarding, and hermes/kimi backend
ResumeRejected (set on resume, not on a fresh run).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant